﻿using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EventBus;
using IdentityServerManagement.Clients;
using IdentityServerManagement.ApiResources;
using IdentityServerManagement.ApiScopes;
using IdentityServerManagement.IdentityResources;

namespace IdentityServerManagement
{
    public class IdentityServerCacheItemInvalidator :
        ILocalEventHandler<EntityChangedEventData<Client>>,
        ILocalEventHandler<EntityChangedEventData<ClientCorsOrigin>>,
        ILocalEventHandler<EntityChangedEventData<IdentityResource>>,
        ILocalEventHandler<EntityChangedEventData<ApiResource>>,
        ILocalEventHandler<EntityChangedEventData<ApiScope>>,
        ITransientDependency
    {
        protected IIdentityServerCacheContext IdentityServerCacheContext { get; }

        public IdentityServerCacheItemInvalidator(IServiceProvider serviceProvider)
        {
            IdentityServerCacheContext = serviceProvider.GetRequiredService<IIdentityServerCacheContext>();
        }

        public virtual async Task HandleEventAsync(EntityChangedEventData<Client> eventData)
        {
            var clientCache = IdentityServerCacheContext.Clients;
            await clientCache.RemoveAsync(eventData.Entity.ClientId, considerUow: true);

            var corsCache = IdentityServerCacheContext.AllowedCorsOrigins;
            await corsCache.RemoveAsync(AllowedCorsOriginsCacheItem.AllOrigins);
        }

        public async Task HandleEventAsync(EntityChangedEventData<ClientCorsOrigin> eventData)
        {
            var corsCache = IdentityServerCacheContext.AllowedCorsOrigins;
            await corsCache.RemoveAsync(AllowedCorsOriginsCacheItem.AllOrigins);
        }

        public virtual async Task HandleEventAsync(EntityChangedEventData<IdentityResource> eventData)
        {
            var cache = IdentityServerCacheContext.IdentityResources;
            await cache.RemoveAsync(eventData.Entity.Name);

            var resourcesCache = IdentityServerCacheContext.Resources;
            await resourcesCache.RemoveAsync(ResourceStore.AllResourcesKey);
        }

        public virtual async Task HandleEventAsync(EntityChangedEventData<ApiResource> eventData)
        {
            var cache = IdentityServerCacheContext.ApiResources;
            await cache.RemoveAsync(ResourceStore.ApiResourceNameCacheKeyPrefix + eventData.Entity.Name);
            await cache.RemoveManyAsync(eventData.Entity.Scopes.Select(x => ResourceStore.ApiResourceScopeNameCacheKeyPrefix + x.Scope));

            var resourcesCache = IdentityServerCacheContext.Resources;
            await resourcesCache.RemoveAsync(ResourceStore.AllResourcesKey);
        }

        public virtual async Task HandleEventAsync(EntityChangedEventData<ApiScope> eventData)
        {
            var cache = IdentityServerCacheContext.ApiScopes;
            await cache.RemoveAsync(eventData.Entity.Name);

            var resourcesCache = IdentityServerCacheContext.Resources;
            await resourcesCache.RemoveAsync(ResourceStore.AllResourcesKey);
        }
    }
}
